/*
 * Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved.
 *
 * OpenArkFE is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *  http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
 * FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#ifndef __BUILTINS_H__
#define __BUILTINS_H__

namespace t2crt {

template <typename T1, typename T2>
class Record : public Object {
  public:
    std::unordered_map<T1, T2> records;
    Record() {}
    ~Record() {}
    Record(Function* ctor, Object* proto) : Object(ctor, proto) {}
    Record(Function* ctor, Object* proto, std::vector<ObjectProp> props) : Object(ctor, proto, props) {}
};

template <typename T>
class Array : public Object {
  public:
    std::vector<T> elements;
    Array(Function* ctor, Object* proto): Object(ctor, proto) {}
    Array(Function* ctor, Object* proto, std::initializer_list<T> l): Object(ctor, proto), elements(l) {}

    T& operator[](int i) {return elements[i];}
    void operator = (const std::vector<T> &v) { elements = v; }
    long size() { return elements.size(); }

    // Put JS Array.prototype props as static fields and methods in this class
    // and add to proplist of Array_ctor.prototype object on system init.

    class Ctor: public Function {
    public:
      Ctor(Function* ctor, Object* proto, Object* prototype_proto) : Function(ctor, proto, prototype_proto) {}
      Array<T>* _new() {
        return new Array<T>(this, this->prototype);
      }
      Array<T>* _new(std::initializer_list<T>l) {
        return new Array<T>(this, this->prototype, l);
      }
    };
    static Ctor ctor;
};

// Create ctor func for 1,2,3 dimension array of given type
// note: must be in sync with format generated by ArrayCtorName in helper.h
#define ARR_CTOR_DEF(type) \
  template <> \
  Array<type>::Ctor                 Array<type>::ctor = Array<type>::Ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); \
  template <> \
  Array<Array<type>*>::Ctor         Array<Array<type>*>::ctor = Array<Array<type>*>::Ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); \
  template <> \
  Array<Array<Array<type>*>*>::Ctor Array<Array<Array<type>*>*>::ctor = Array<Array<Array<type>*>*>::Ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype);

class JSON : public Object {
  // TODO
};

class RegExp : public Object {
  // TODO
};

class Number : public Object {
public:
  // TODO
  class Ctor : public t2crt::Function {
  public:
    Ctor(t2crt::Function* ctor, t2crt::Object* proto, t2crt::Object* prototype_proto) : t2crt::Function(ctor, proto, prototype_proto) { }
    virtual const char* __GetClassName() const {return "Number ";}
  };
  static Ctor ctor;
};

} // namespace t2crt

using t2crt::Record;
using t2crt::JSON;
using t2crt::RegExp;
#endif // __BUILTINS_H__
